/* --------------------------------------------------------------- */
/* class Application, the Application interface in GTK.            */
/* Authors:                                                        */
/* Emilio Blazquez Sierra                                          */
/* Francisco Fernandez Castaño                                     */
/* Maria Jesus Ciudad Trujillo                                     */
/* --------------------------------------------------------------- */


#include "Application.h"

Application::Application()
  : m_VBox(false, 0),
    m_HPaned(),
    m_MBar(),
    m_MItem("File"),
    m_Submenu(),
    m_MItemShapes("Add"),
    m_VBBox(),
    m_VBBox2(),
    m_ButtonEdit("Change mode"),
    r_scale("Scale"),
    m_ButtonRotate("Rotate"),
    r_translate("Translate"),
    del("Delete"),
    Extr("Extrude"),
    select_all("Select All"),
    select_inverse("Select Inverse"),
    deselect_all("Deselect All"),
    edobmod("Object Mode"),
    editmode(false)

{
  // http://en.wikipedia.org/wiki/Yame,_Fukuoka
  set_title("YaMe: Yet another Modeling environment");

  //Load the Glade file and instiate its widgets:


  //Rotation Window
  Glib::RefPtr<Gnome::Glade::Xml> refXml;
  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/rotate.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("trans", rotateWindow);
  refXml->get_widget("button1", button3);
  refXml->get_widget("rx", rotx);
  refXml->get_widget("X", rx);
  refXml->get_widget("Y", ry);
  refXml->get_widget("Z", rz);

  //Scale Window

  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/scale.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("scal", scaleWindow);
  refXml->get_widget("button2", buttons);
  refXml->get_widget("sx", scax);
  refXml->get_widget("X", sx);
  refXml->get_widget("Y", sy);
  refXml->get_widget("Z", sz);

  //Extrude Window

  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/extrude.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("extrudewin", extrudeWin);
  refXml->get_widget("buttone", buttonex);
  refXml->get_widget("distex", distext);

  //Translate Window

  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/translate.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("trans", translateWindow);
  refXml->get_widget("buttontr", buttont);
  refXml->get_widget("transx", tx);
  refXml->get_widget("transy", ty);
  refXml->get_widget("transz", tz);


  //Error Window

  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/erred.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("erroredit", error);

  //Import Window
  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/importorj.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("impor", impwin);
  refXml->get_widget("buttonimp", buttonim);
  refXml->get_widget("pathi", pathimp);

  //Export Window

  try
    {
      refXml = Gnome::Glade::Xml::create("./gladeFiles/export.glade");
    }
  catch(const Gnome::Glade::XmlError& ex)
    {
      std::cerr << ex.what() << std::endl;
    }
  refXml->get_widget("export", expwin);
  refXml->get_widget("buttonexp", buttonexport);
  refXml->get_widget("pathe", pathexp);



  // Get automatically redrawn if any of their children changed allocation.
  set_reallocate_redraws(true);

  add(m_VBox);

  //Some Gtk aspects of interface
  m_Shapes_menu = m_Scene.create_add_menu();
  m_FileMenu = create_file_menu();

  m_Scene.set_size_request(600, 600);
  m_VBox.pack_start(m_MBar);
  m_VBox.add(edobmod);
  m_MBar.append(m_MItem);
  m_MItem.set_submenu(*m_FileMenu);
  m_MBar.append(m_MItemShapes);
  m_MItemShapes.set_submenu(*m_Shapes_menu);
  m_VBox.pack_start(m_HPaned);
  m_HPaned.pack_start(m_VBBox);
  m_HPaned.add(m_Scene);
  m_HPaned.add(m_VBBox2);

  //Left buttons
  m_VBBox.pack_start(m_ButtonEdit, Gtk::PACK_SHRINK, 0);
  m_VBBox.add(select_all);
  m_VBBox.add(select_inverse);
  m_VBBox.add(deselect_all);

  //Right buttons
  m_VBBox2.pack_start(m_ButtonRotate, Gtk::PACK_SHRINK, 0);
  m_VBBox2.add(r_scale);
  m_VBBox2.add(r_translate);
  m_VBBox2.add(del);
  m_VBBox2.add(Extr);

  connects(); //Connect signals with buttons

  //
  // Show window.
  //

  show_all();
}


Gtk::Menu* Application::create_file_menu()
{
  Gtk::Menu* File_Menu = Gtk::manage(new Gtk::Menu());
  {
    Gtk::Menu::MenuList& menu_list = File_Menu->items();

    // New
    menu_list.push_back(Gtk::Menu_Helpers::MenuElem("New",sigc::bind(sigc::mem_fun(*this, &Application::New),0)));

    // Import
    menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Import",sigc::bind(sigc::mem_fun(*this, &Application::Import),0)));

    // Export
    menu_list.push_back(Gtk::Menu_Helpers::MenuElem("Export",sigc::bind(sigc::mem_fun(*this, &Application::Export),0)));

  }
  return File_Menu;
}


void Application::New(int x)
{
  m_Scene.DeleteAll();
}

void Application::Import(int x)
{
  impwin->show();
}

void Application::Export(int x)
{
  expwin->show();
}

Application::~Application()
{
  delete rotateWindow;
}

void Application::on_button_rotate_clicked()
{
  rotateWindow->show();
}

bool Application::on_key_press_event(GdkEventKey* event)
{
  switch (event->keyval) {
  case GDK_Escape: /* Exit Program whit Escape key*/
    Gtk::Main::quit();
    break;
  case GDK_s: // Scale with s key
    on_scale_button_press();
    break;
  case GDK_g: //Translate with g key
    on_translate_button_press();
    break;
  case GDK_r:  // Rotate with r key
    on_button_rotate_clicked();
    break;
  case GDK_Delete: //Delete with Delete key
    on_delete();
    break;
  case GDK_e: // Extrude with e key
    on_extrude();
    break;
  default:
    return true;
  }

  m_Scene.invalidate(); // Redraw the scene on gtk widget display

  return true;
}

void Application::on_rotate_button()
{
  double r = 0;
  //Conversion from ustring to double
  Glib::ustring text;
  std::string textstr;
  text = rotx->get_text();
  textstr = text.raw();
  std::istringstream i(textstr);
  i >> r;
  if(rx->get_active() && ry->get_active() && rz->get_active()){
    m_Scene.rotate((GLdouble) r, XYZ);
  }else{
    if(rx->get_active() && ry->get_active())
      m_Scene.rotate((GLdouble) r, XY);
    else
      if(ry->get_active() && rz->get_active())
	m_Scene.rotate((GLdouble) r, XZ);
      else
	if(ry->get_active() && rz->get_active())
	  m_Scene.rotate((GLdouble) r, YZ);
	else{
	  if(rx->get_active())
	    m_Scene.rotate((GLdouble) r, X);
	  if(ry->get_active())
	    m_Scene.rotate((GLdouble) r, Y);
	  if(rz->get_active())
	    m_Scene.rotate((GLdouble) r, Z);

	}
  }
  rotx->delete_text(0,10); //Clean window
  rx->set_active(false);
  ry->set_active(false);
  rz->set_active(false);

  m_Scene.invalidate(); // Redraw the scene on gtk widget display
  rotateWindow->hide();

}
void Application::on_scale_button_press()
{
  scaleWindow->show();
}
void Application::on_scale_button()
{
  double s = 0;
  //Conversion from ustring to double
  Glib::ustring text;
  std::string textstr;
  text = scax->get_text();
  textstr = text.raw();
  std::istringstream i(textstr);
  i >> s;
  if(sx->get_active() && sy->get_active() && sz->get_active()){
    m_Scene.scale((GLdouble) s, XYZ);
  }else{
    if(sx->get_active() && sy->get_active())
      m_Scene.scale((GLdouble) s, XY);
    else
      if(sy->get_active() && sz->get_active())
	m_Scene.scale((GLdouble) s, XZ);
      else
	if(sy->get_active() && sz->get_active())
	  m_Scene.scale((GLdouble) s, YZ);
	else{
	  if(sx->get_active())
	    m_Scene.scale((GLdouble) s, X);
	  if(sy->get_active())
	    m_Scene.scale((GLdouble) s, Y);
	  if(sz->get_active())
	    m_Scene.scale((GLdouble) s, Z);

	}
  }
  scax->delete_text(0,10); //Clean Window
  sx->set_active(false);
  sy->set_active(false);
  sz->set_active(false);
  m_Scene.invalidate(); // Redraw the scene on gtk widget display
  scaleWindow->hide();

}

void Application::on_translate_button_press()
{
  translateWindow->show();
}

void Application::on_translate_button()
{
  double position[3];
  Glib::ustring text;
  std::string textstr;

  //x
  text = tx->get_text();
  textstr = text.raw();
  std::istringstream i(textstr);
  i >> position[0];
  tx->delete_text(0,10);

  //y
  text = ty->get_text();
  textstr = text.raw();
  std::istringstream j(textstr);
  j >> position[1];
  ty->delete_text(0,10);


  //z
  text = tz->get_text();
  textstr = text.raw();
  std::istringstream k(textstr);
  k >> position[2];
  tz->delete_text(0,10);

  Vertex3D translatePos(position);
  m_Scene.move(translatePos);
  m_Scene.invalidate(); // Redraw the scene on gtk widget display
  translateWindow->hide();
}

void Application::on_edit_button_click()
{
  if(m_Scene.get_state() == NORMAL && m_Scene.get_n_selected_objects() != 1)
    error->show();
  else{
    m_Scene.edit_button();
    if(!editmode){
      edobmod.set_text("Edit Mode");
      editmode = true;
    }else{
      editmode = false;
      edobmod.set_text("Object Mode");
    }
  }
}
void Application::on_delete()
{
  m_Scene.delete_objects();
}
void Application::on_extrude()
{
  extrudeWin->show();
}
void Application::on_extrude_action()
{
  double s = 0;
  //Conversion from ustring to double
  Glib::ustring text;
  std::string textstr;
  text = distext->get_text();
  textstr = text.raw();
  std::istringstream i(textstr);
  i >> s;
  m_Scene.extrude(s);
  distext->delete_text(0,10); //Clean Window
  m_Scene.invalidate(); // Redraw the scene on gtk widget display
  extrudeWin->hide();
}
void Application::selectall()
{
  m_Scene.selectall();
}
void Application::selectinverse()
{
  m_Scene.selectinverse();
}
void Application::deselectall()
{
  m_Scene.deselectall();
}
void Application::connects()
{

  buttont->signal_clicked().connect(
				    sigc::mem_fun(*this, &Application::on_translate_button));

  buttons->signal_clicked().connect(
				    sigc::mem_fun(*this, &Application::on_scale_button));

  button3->signal_clicked().connect(
				    sigc::mem_fun(*this, &Application::on_rotate_button));

  buttonex->signal_clicked().connect(
				     sigc::mem_fun(*this, &Application::on_extrude_action));


  m_ButtonEdit.signal_clicked().connect(
					sigc::mem_fun(*this, &Application::on_edit_button_click));

  m_ButtonRotate.signal_clicked().connect(
					  sigc::mem_fun(*this, &Application::on_button_rotate_clicked));
  r_scale.signal_clicked().connect(
				   sigc::mem_fun(*this, &Application::on_scale_button_press));
  r_translate.signal_clicked().connect(
				       sigc::mem_fun(*this, &Application::on_translate_button_press));
  Extr.signal_clicked().connect(
				sigc::mem_fun(*this, &Application::on_extrude));
  del.signal_clicked().connect(
			       sigc::mem_fun(*this, &Application::on_delete));

  select_all.signal_clicked().connect(
				      sigc::mem_fun(*this, &Application::selectall));

  select_inverse.signal_clicked().connect(
					  sigc::mem_fun(*this, &Application::selectinverse));

  deselect_all.signal_clicked().connect(
					sigc::mem_fun(*this, &Application::deselectall));

  buttonim->signal_clicked().connect(
				     sigc::mem_fun(*this, &Application::import_action));

  buttonexport->signal_clicked().connect(
					 sigc::mem_fun(*this, &Application::export_action));


}
void Application::import_action()
{
  Glib::ustring text;
  std::string path;
  text = pathimp->get_text();
  path = text.raw();

  //Call to import function

  pathimp->delete_text(0,20);
  impwin->hide();
}

void Application::export_action()
{
  Glib::ustring text;
  std::string path;
  text = pathexp->get_text();
  path = text.raw();

  //Call to export function

  pathexp->delete_text(0,20);
  expwin->hide();
}
